﻿using System;

public class OrthographicCamera:Camera
{
    public OrthographicCamera(Image img)
    {
        this.img = img;
    }
    public override void render(Scene scene)
    {
        Console.WriteLine(DateTime.Now.TimeOfDay.ToString() + " Rendering Otroghraphic...");
        float pixelCentreX;
        float pixelCentreY;
        int numOfLights;
        int intersectedPrimitive = -1;
        bool inShadow;
        LightIntensity finalColor;
        Ray ray;
        Ray rayToLight;
        Ray ray1, ray2, ray3, ray4;//do antyaliasingu
        for (int i = 0; i < img.width; i++)
        {
            for (int j = 0; j < img.height; j++)
            {
                pixelCentreX = -(img.width*img.pixelWidth/2) + (i + 0.5f) * img.pixelWidth;
                pixelCentreY = (img.height*img.pixelHeight/2) - (j + 0.5f) * img.pixelHeight;
                ray = new Ray(new Vector3(pixelCentreX, pixelCentreY, 0), new Vector3(0, 0, -1), true);
                ray1 = new Ray(new Vector3(pixelCentreX-img.pixelWidth/2, pixelCentreY+img.pixelHeight/2, 0), new Vector3(0, 0, -1), true);//do antyaliasingu
                ray2 = new Ray(new Vector3(pixelCentreX+img.pixelWidth/2, pixelCentreY+img.pixelHeight/2, 0), new Vector3(0, 0, -1), true);//do antyaliasingu
                ray3 = new Ray(new Vector3(pixelCentreX+img.pixelWidth/2, pixelCentreY-img.pixelHeight/2, 0), new Vector3(0, 0, -1), true);//do antyaliasingu
                ray4 = new Ray(new Vector3(pixelCentreX - img.pixelWidth / 2, pixelCentreY - img.pixelHeight / 2, 0), new Vector3(0, 0, -1), true);//do antyaliasingu
                //img.setPixel(i, j, antialiasing(1, 4, img.pixelWidth, img.pixelHeight, new Vector3(0, 0, -1), primitive, ray, ray1, ray2, ray3, ray4));//do antyaliasingu
                intersectedPrimitive = -1;
                for (int k = 0; k < scene.objectsNumber(); k++)
                {
                    if (scene.objects[k].intersect(ray))
                        intersectedPrimitive = k;
                }
                if (intersectedPrimitive >= 0)
                {
                    numOfLights = 0;
                    inShadow = false;
                    finalColor = new LightIntensity();
                    for (int l = 0; l < scene.lightsNumber(); l++)
                    {
                        numOfLights++;
                        rayToLight = new Ray(ray.destination, scene.lights[l].position, false);
                        for (int kk = 0; kk < scene.objectsNumber(); kk++)
                        {
                            //if (kk != intersectedPrimitive)
                            //inShadow = primitive[kk].intersect(rayToLight);
                            if (scene.objects[kk].intersect(rayToLight) && (rayToLight.destination-ray.destination).length()<rayToLight.direction.length())
                            {
                                inShadow = true;
                                kk = scene.objectsNumber();
                            }
                        }
                        //inShadow = false;//test
                        finalColor += scene.lights[l].Lighting(ray.destination, new Vector3(pixelCentreX, pixelCentreY, 0), scene.objects[intersectedPrimitive], inShadow);
                    }
                    if (numOfLights != 0)
                        finalColor /= numOfLights;
                    //img.setPixel(i, j, primitive[k].color);
                    img.setPixel(i, j, finalColor);
                }
                else
                {
                    img.setPixel(i, j, new LightIntensity(0, 0, 0));//bez antyaliasingu
                }
            }
        }
        img.saveImage("obraz.bmp");
        Console.WriteLine(DateTime.Now.TimeOfDay.ToString() + " Rendering finished");
    }
    public LightIntensity antialiasing(int minSamples, int maxSamples, float pixelWidth, float pixelHeight, Vector3 v, Primitive[] p, Ray r0, Ray r1, Ray r2, Ray r3, Ray r4)
    {
        LightIntensity li0, li1, li2, li3, li4;
        li0 = new LightIntensity(0, 0, 0);
        li1 = new LightIntensity(0, 0, 0);
        li2 = new LightIntensity(0, 0, 0);
        li3 = new LightIntensity(0, 0, 0);
        li4 = new LightIntensity(0, 0, 0);
        for (int i = 0; i < p.Length; i++)
        {
            if (p[i].intersect(r0))
                li0 = p[i].material.Kd;
            if (p[i].intersect(r1))
                li1 = p[i].material.Kd;
            if (p[i].intersect(r2))
                li2 = p[i].material.Kd;
            if (p[i].intersect(r3))
                li3 = p[i].material.Kd;
            if (p[i].intersect(r4))
                li4 = p[i].material.Kd;
        }
        if(minSamples<maxSamples)
        {
            //LightIntensity liAvg = new LightIntensity((li1.r+li2.r+li3.r+li4.r)/4,(li1.g+li2.g+li3.g+li4.g)/4,(li1.b+li2.b+li3.b+li4.b)/4);
            /*if (Math.Abs(li0.r - liAvg.r) > difR || Math.Abs(li0.g - liAvg.g) > difG || Math.Abs(li0.b - liAvg.b) > difB)
            {
                return (antialiasing(minSamples++, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x - pixelWidth / 4, r0.origin.y + pixelHeight / 4, r0.origin.z), v, true), r1, new Ray(new Vector3(r0.origin.x, r0.origin.y + pixelHeight / 2, r0.origin.z), v, true), r0, new Ray(new Vector3(r0.origin.x - pixelWidth / 2, r0.origin.y, r0.origin.z), v, true))
                        + antialiasing(minSamples++, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x + pixelWidth / 4, r0.origin.y + pixelHeight / 4, r0.origin.z), v, true), new Ray(new Vector3(r0.origin.x, r0.origin.y + pixelHeight / 2, r0.origin.z), v, true), r2, new Ray(new Vector3(r0.origin.x + pixelWidth / 2, r0.origin.y, r0.origin.z), v, true),r0)
                        + antialiasing(minSamples++, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x + pixelWidth / 4, r0.origin.y - pixelHeight / 4, r0.origin.z), v, true), r0, new Ray(new Vector3(r0.origin.x + pixelWidth / 2, r0.origin.y, r0.origin.z), v, true), r3, new Ray(new Vector3(r0.origin.x, r0.origin.y - pixelHeight/2, r0.origin.z), v, true))
                        + antialiasing(minSamples++, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x - pixelWidth / 4, r0.origin.y - pixelHeight / 4, r0.origin.z), v, true), new Ray(new Vector3(r0.origin.x - pixelWidth / 2, r0.origin.y, r0.origin.z), v, true), r0, new Ray(new Vector3(r0.origin.x, r0.origin.y - pixelHeight / 2, r0.origin.z), v, true), r4)) / 4;
            }
            else 
            {
                return li0;
            }*/
            if (Math.Abs(li0.r - li1.r) > difR || Math.Abs(li0.g - li1.g) > difG || Math.Abs(li0.b - li1.b) > difB)
            {
                li1 = (antialiasing(++minSamples, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x - pixelWidth / 4, r0.origin.y + pixelHeight / 4, r0.origin.z), v, true), r1, new Ray(new Vector3(r0.origin.x, r0.origin.y + pixelHeight / 2, r0.origin.z), v, true), r0, new Ray(new Vector3(r0.origin.x - pixelWidth / 2, r0.origin.y, r0.origin.z), v, true)));
            }
            if (Math.Abs(li0.r - li2.r) > difR || Math.Abs(li0.g - li2.g) > difG || Math.Abs(li0.b - li2.b) > difB)
            {
                li2 = (antialiasing(++minSamples, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x + pixelWidth / 4, r0.origin.y + pixelHeight / 4, r0.origin.z), v, true), new Ray(new Vector3(r0.origin.x, r0.origin.y + pixelHeight / 2, r0.origin.z), v, true), r2, new Ray(new Vector3(r0.origin.x + pixelWidth / 2, r0.origin.y, r0.origin.z), v, true), r0));
            }
            if (Math.Abs(li0.r - li3.r) > difR || Math.Abs(li0.g - li3.g) > difG || Math.Abs(li0.b - li3.b) > difB)
            {
                li3 = (antialiasing(++minSamples, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x + pixelWidth / 4, r0.origin.y - pixelHeight / 4, r0.origin.z), v, true), r0, new Ray(new Vector3(r0.origin.x + pixelWidth / 2, r0.origin.y, r0.origin.z), v, true), r3, new Ray(new Vector3(r0.origin.x, r0.origin.y - pixelHeight / 2, r0.origin.z), v, true)));
            }
            if (Math.Abs(li0.r - li4.r) > difR || Math.Abs(li0.g - li4.g) > difG || Math.Abs(li0.b - li4.b) > difB)
            {
                li4 = (antialiasing(++minSamples, maxSamples, pixelWidth / 2, pixelHeight / 2, v, p, new Ray(new Vector3(r0.origin.x - pixelWidth / 4, r0.origin.y - pixelHeight / 4, r0.origin.z), v, true), new Ray(new Vector3(r0.origin.x - pixelWidth / 2, r0.origin.y, r0.origin.z), v, true), r0, new Ray(new Vector3(r0.origin.x, r0.origin.y - pixelHeight / 2, r0.origin.z), v, true), r4));
            }
            return (li1+li2+li3+li4) / 4;
            //return ((li1 + li0) / 2 + (li2 + li0) / 2 + (li3 + li0) / 2 + (li4 + li0) / 2) / 4;
        }
        else
        {
            return new LightIntensity(((li1.r + li2.r + li3.r + li4.r) / 2 + 2 * li0.r) / 4, ((li1.g + li2.g + li3.g + li4.g) / 2 + 2 * li0.g) / 4, ((li1.b + li2.b + li3.b + li4.b) / 2 + 2 * li0.b) / 4);
        }
    }
}
